From b079d72c1075de9e28d3f4f3eaa3f0efb26c11f7 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Mon, 4 Jun 2007 13:57:08 -0600 Subject: [PATCH] [IA64] Allow dynamic allocation of dom0 fw_tables This address Xensource bugzilla #980 Signed-off-by: Isaku Yamahata --- tools/libxc/ia64/xc_dom_ia64_util.c | 31 +++-- tools/libxc/ia64/xc_dom_ia64_util.h | 2 +- xen/arch/ia64/xen/dom_fw_common.c | 42 ++++--- xen/arch/ia64/xen/dom_fw_dom0.c | 171 ++++++++++++++++----------- xen/arch/ia64/xen/dom_fw_domu.c | 73 +++++++----- xen/arch/ia64/xen/dom_fw_utils.c | 156 +++++++++++++++++++----- xen/include/asm-ia64/dom_fw.h | 5 +- xen/include/asm-ia64/dom_fw_common.h | 14 ++- xen/include/asm-ia64/dom_fw_dom0.h | 6 +- xen/include/asm-ia64/dom_fw_domu.h | 2 +- xen/include/asm-ia64/dom_fw_utils.h | 4 + 11 files changed, 342 insertions(+), 164 deletions(-) diff --git a/tools/libxc/ia64/xc_dom_ia64_util.c b/tools/libxc/ia64/xc_dom_ia64_util.c index f586bc66a1..d1d15f405c 100644 --- a/tools/libxc/ia64/xc_dom_ia64_util.c +++ b/tools/libxc/ia64/xc_dom_ia64_util.c @@ -18,6 +18,7 @@ * */ +#include #include "xg_private.h" #include "xc_dom.h" #include "asm/dom_fw.h" @@ -114,12 +115,12 @@ xen_ia64_dom_fw_setup(struct xc_dom_image *d, uint64_t brkimm, { int rc = 0; void *imva_hypercall_base = NULL; - void *imva_tables_base = NULL; + struct fw_tables *fw_tables = NULL; struct fake_acpi_tables *imva = NULL; struct xen_ia64_boot_param *bp = NULL; BUILD_BUG_ON(sizeof(struct fw_tables) > - (FW_TABLES_END_PADDR - FW_TABLES_BASE_PADDR)); + (FW_TABLES_END_PADDR_MIN - FW_TABLES_BASE_PADDR)); /* Create page for hypercalls. */ imva_hypercall_base = xen_ia64_dom_fw_map(d, FW_HYPERCALL_BASE_PADDR); @@ -129,11 +130,17 @@ xen_ia64_dom_fw_setup(struct xc_dom_image *d, uint64_t brkimm, } /* Create page for FW tables. */ - imva_tables_base = xen_ia64_dom_fw_map(d, FW_TABLES_BASE_PADDR); - if (imva_tables_base == NULL) { + fw_tables = (struct fw_tables*)xen_ia64_dom_fw_map(d, FW_TABLES_BASE_PADDR); + if (fw_tables == NULL) { rc = -errno; goto out; } + memset(fw_tables, 0, FW_TABLES_END_PADDR_MIN - FW_TABLES_BASE_PADDR); + BUILD_BUG_ON(FW_END_PADDR_MIN != FW_TABLES_END_PADDR_MIN); + fw_tables->fw_tables_size = FW_TABLES_END_PADDR_MIN - FW_TABLES_BASE_PADDR; + fw_tables->fw_end_paddr = FW_END_PADDR_MIN; + fw_tables->fw_tables_end_paddr = FW_TABLES_END_PADDR_MIN; + fw_tables->num_mds = 0; /* Create page for acpi tables. */ imva = (struct fake_acpi_tables *) @@ -150,14 +157,22 @@ xen_ia64_dom_fw_setup(struct xc_dom_image *d, uint64_t brkimm, rc = -errno; goto out; } - rc = dom_fw_init(d, brkimm, bp, imva_tables_base, + rc = dom_fw_init(d, brkimm, bp, fw_tables, (unsigned long)imva_hypercall_base, maxmem); - + BUG_ON(fw_tables->fw_tables_size < sizeof(*fw_tables) + + sizeof(fw_tables->efi_memmap[0]) * fw_tables->num_mds); + + /* clear domain builder internal use member */ + fw_tables->fw_tables_size = 0; + fw_tables->fw_end_paddr = 0; + fw_tables->fw_tables_end_paddr = 0; + fw_tables->num_mds = 0; + out: if (imva_hypercall_base != NULL) xen_ia64_dom_fw_unmap(d, imva_hypercall_base); - if (imva_tables_base != NULL) - xen_ia64_dom_fw_unmap(d, imva_tables_base); + if (fw_tables != NULL) + xen_ia64_dom_fw_unmap(d, fw_tables); if (imva != NULL) xen_ia64_dom_fw_unmap(d, imva); if (bp != NULL) diff --git a/tools/libxc/ia64/xc_dom_ia64_util.h b/tools/libxc/ia64/xc_dom_ia64_util.h index 1a512ab985..66dfa41f01 100644 --- a/tools/libxc/ia64/xc_dom_ia64_util.h +++ b/tools/libxc/ia64/xc_dom_ia64_util.h @@ -14,6 +14,6 @@ int xen_ia64_dom_fw_setup(struct xc_dom_image *d, uint64_t brkimm, unsigned long bp_mpa, unsigned long maxmem); #define efi_systable_init_dom0(tables) assert(0) -#define complete_dom0_memmap(d, tables, maxmem, num_mds) ({assert(0);0;}) +#define complete_dom0_memmap(d, tables) ({assert(0);0;}) #endif /* XC_IA64_DOM_IA64_UTIL_H */ diff --git a/xen/arch/ia64/xen/dom_fw_common.c b/xen/arch/ia64/xen/dom_fw_common.c index 37c3107843..43ed21e6d3 100644 --- a/xen/arch/ia64/xen/dom_fw_common.c +++ b/xen/arch/ia64/xen/dom_fw_common.c @@ -35,22 +35,17 @@ #include void -xen_ia64_efi_make_md(struct fw_tables *tables, int *index, +xen_ia64_efi_make_md(efi_memory_desc_t *md, uint32_t type, uint64_t attr, uint64_t start, uint64_t end) { - efi_memory_desc_t *md = &tables->efi_memmap[*index]; md->type = type; md->pad = 0; md->phys_addr = start; md->virt_addr = 0; md->num_pages = (end - start) >> EFI_PAGE_SHIFT; md->attribute = attr; - - (*index)++; } -#define MAKE_MD(typ, attr, start, end) \ - xen_ia64_efi_make_md((tables), &(i), (typ), (attr), (start), (end)) #define EFI_HYPERCALL_PATCH(tgt, call) \ do { \ @@ -422,7 +417,7 @@ dom_fw_init(domain_t *d, int num_mds, i; int fpswa_supported = 0; - memset(tables, 0, sizeof(struct fw_tables)); + /* Caller must zero-clear fw_tables */ /* EFI systab. */ tables->efi_systab.hdr.signature = EFI_SYSTEM_TABLE_SIGNATURE; @@ -514,17 +509,25 @@ dom_fw_init(domain_t *d, (void *)FW_HYPERCALL_FPSWA_ENTRY_PADDR; } - i = 0; /* Used by MAKE_MD */ - + tables->num_mds = 0; /* hypercall patches live here, masquerade as reserved PAL memory */ - MAKE_MD(EFI_PAL_CODE,EFI_MEMORY_WB|EFI_MEMORY_RUNTIME, - FW_HYPERCALL_BASE_PADDR, FW_HYPERCALL_END_PADDR); + xen_ia64_efi_make_md(&tables->efi_memmap[tables->num_mds], + EFI_PAL_CODE, EFI_MEMORY_WB | EFI_MEMORY_RUNTIME, + FW_HYPERCALL_BASE_PADDR, FW_HYPERCALL_END_PADDR); + tables->num_mds++; /* Create dom0/domu md entry for fw and cpi tables area. */ - MAKE_MD(EFI_ACPI_MEMORY_NVS, EFI_MEMORY_WB | EFI_MEMORY_RUNTIME, - FW_ACPI_BASE_PADDR, FW_ACPI_END_PADDR); - MAKE_MD(EFI_RUNTIME_SERVICES_DATA, EFI_MEMORY_WB | EFI_MEMORY_RUNTIME, - FW_TABLES_BASE_PADDR, FW_TABLES_END_PADDR); + xen_ia64_efi_make_md(&tables->efi_memmap[tables->num_mds], + EFI_ACPI_MEMORY_NVS, + EFI_MEMORY_WB | EFI_MEMORY_RUNTIME, + FW_ACPI_BASE_PADDR, FW_ACPI_END_PADDR); + tables->num_mds++; + xen_ia64_efi_make_md(&tables->efi_memmap[tables->num_mds], + EFI_RUNTIME_SERVICES_DATA, + EFI_MEMORY_WB | EFI_MEMORY_RUNTIME, + FW_TABLES_BASE_PADDR, + tables->fw_tables_end_paddr); + tables->num_mds++; if (!xen_ia64_is_dom0(d) || xen_ia64_is_running_on_sim(d)) { /* DomU (or hp-ski). @@ -536,26 +539,27 @@ dom_fw_init(domain_t *d, * and console page. * see ia64_setup_memmap() @ xc_dom_boot.c */ - num_mds = complete_domu_memmap(d, tables, maxmem, i, + num_mds = complete_domu_memmap(d, tables, maxmem, XEN_IA64_MEMMAP_INFO_PFN(bp), XEN_IA64_MEMMAP_INFO_NUM_PAGES(bp)); } else { /* Dom0. We must preserve ACPI data from real machine, as well as IO areas. */ - num_mds = complete_dom0_memmap(d, tables, maxmem, i); + num_mds = complete_dom0_memmap(d, tables); } if (num_mds < 0) return num_mds; + BUG_ON(num_mds != tables->num_mds); /* Display memmap. */ - for (i = 0 ; i < num_mds; i++) + for (i = 0 ; i < tables->num_mds; i++) print_md(&tables->efi_memmap[i]); /* Fill boot_param */ bp->efi_systab = FW_FIELD_MPA(efi_systab); bp->efi_memmap = FW_FIELD_MPA(efi_memmap); - bp->efi_memmap_size = num_mds * sizeof(efi_memory_desc_t); + bp->efi_memmap_size = tables->num_mds * sizeof(efi_memory_desc_t); bp->efi_memdesc_size = sizeof(efi_memory_desc_t); bp->efi_memdesc_version = EFI_MEMDESC_VERSION; bp->command_line = 0; diff --git a/xen/arch/ia64/xen/dom_fw_dom0.c b/xen/arch/ia64/xen/dom_fw_dom0.c index 2860c436b8..4eec44b157 100644 --- a/xen/arch/ia64/xen/dom_fw_dom0.c +++ b/xen/arch/ia64/xen/dom_fw_dom0.c @@ -32,6 +32,7 @@ #include #include #include +#include #include @@ -158,21 +159,26 @@ void __init efi_systable_init_dom0(struct fw_tables *tables) } static void __init -setup_dom0_memmap_info(struct domain *d, struct fw_tables *tables, int *num_mds) +setup_dom0_memmap_info(struct domain *d, struct fw_tables *tables) { int i; + size_t size; + unsigned int num_pages; efi_memory_desc_t *md; efi_memory_desc_t *last_mem_md = NULL; xen_ia64_memmap_info_t *memmap_info; unsigned long paddr_start; unsigned long paddr_end; - for (i = *num_mds - 1; i >= 0; i--) { + size = sizeof(*memmap_info) + + (tables->num_mds + 1) * sizeof(tables->efi_memmap[0]); + num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; + for (i = tables->num_mds - 1; i >= 0; i--) { md = &tables->efi_memmap[i]; if (md->attribute == EFI_MEMORY_WB && md->type == EFI_CONVENTIONAL_MEMORY && md->num_pages > - 2 * (1UL << (PAGE_SHIFT - EFI_PAGE_SHIFT))) { + ((num_pages + 1) << (PAGE_SHIFT - EFI_PAGE_SHIFT))) { last_mem_md = md; break; } @@ -186,45 +192,71 @@ setup_dom0_memmap_info(struct domain *d, struct fw_tables *tables, int *num_mds) } paddr_end = last_mem_md->phys_addr + (last_mem_md->num_pages << EFI_PAGE_SHIFT); - paddr_start = (paddr_end - PAGE_SIZE) & PAGE_MASK; - last_mem_md->num_pages -= - (paddr_end - paddr_start) / (1UL << EFI_PAGE_SHIFT); + paddr_start = (paddr_end - (num_pages << PAGE_SHIFT)) & PAGE_MASK; + last_mem_md->num_pages -= (paddr_end - paddr_start) >> EFI_PAGE_SHIFT; - md = &tables->efi_memmap[*num_mds]; - (*num_mds)++; + md = &tables->efi_memmap[tables->num_mds]; + tables->num_mds++; md->type = EFI_RUNTIME_SERVICES_DATA; md->phys_addr = paddr_start; md->virt_addr = 0; - md->num_pages = 1UL << (PAGE_SHIFT - EFI_PAGE_SHIFT); + md->num_pages = num_pages << (PAGE_SHIFT - EFI_PAGE_SHIFT); md->attribute = EFI_MEMORY_WB; - memmap_info = domain_mpa_to_imva(d, md->phys_addr); - BUG_ON(*num_mds > NUM_MEM_DESCS); + BUG_ON(tables->fw_tables_size < + sizeof(*tables) + + sizeof(tables->efi_memmap[0]) * tables->num_mds); + /* with this sort, md doesn't point memmap table */ + sort(tables->efi_memmap, tables->num_mds, + sizeof(efi_memory_desc_t), efi_mdt_cmp, NULL); + memmap_info = domain_mpa_to_imva(d, paddr_start); memmap_info->efi_memdesc_size = sizeof(md[0]); memmap_info->efi_memdesc_version = EFI_MEMORY_DESCRIPTOR_VERSION; - memmap_info->efi_memmap_size = *num_mds * sizeof(md[0]); - memcpy(&memmap_info->memdesc, &tables->efi_memmap[0], - memmap_info->efi_memmap_size); - d->shared_info->arch.memmap_info_num_pages = 1; - d->shared_info->arch.memmap_info_pfn = md->phys_addr >> PAGE_SHIFT; + memmap_info->efi_memmap_size = tables->num_mds * sizeof(md[0]); + dom_fw_copy_to(d, + paddr_start + offsetof(xen_ia64_memmap_info_t, memdesc), + &tables->efi_memmap[0], memmap_info->efi_memmap_size); + d->shared_info->arch.memmap_info_num_pages = num_pages; + d->shared_info->arch.memmap_info_pfn = paddr_start >> PAGE_SHIFT; +} - sort(tables->efi_memmap, *num_mds, sizeof(efi_memory_desc_t), - efi_mdt_cmp, NULL); +/* setup_guest() @ libxc/xc_linux_build() arranges memory for domU. + * however no one arranges memory for dom0, + * instead we allocate pages manually. + */ +static void +assign_new_domain0_range(struct domain *d, const efi_memory_desc_t * md) +{ + if (md->type == EFI_PAL_CODE || + md->type == EFI_RUNTIME_SERVICES_DATA || + md->type == EFI_CONVENTIONAL_MEMORY) { + unsigned long start = md->phys_addr & PAGE_MASK; + unsigned long end = + md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT); + unsigned long addr; + + if (end == start) { + /* md->num_pages = 0 is allowed. */ + return; + } + + for (addr = start; addr < end; addr += PAGE_SIZE) + assign_new_domain0_page(d, addr); + } } /* Complete the dom0 memmap. */ int __init -complete_dom0_memmap(struct domain *d, - struct fw_tables *tables, - unsigned long maxmem, int num_mds) +complete_dom0_memmap(struct domain *d, struct fw_tables *tables) { - efi_memory_desc_t *md; u64 addr; void *efi_map_start, *efi_map_end, *p; u64 efi_desc_size; int i; - unsigned long dom_mem = maxmem - (d->tot_pages << PAGE_SHIFT); + + for (i = 0; i < tables->num_mds; i++) + assign_new_domain0_range(d, &tables->efi_memmap[i]); /* Walk through all MDT entries. Copy all interesting entries. */ @@ -234,7 +266,7 @@ complete_dom0_memmap(struct domain *d, for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { const efi_memory_desc_t *md = p; - efi_memory_desc_t *dom_md = &tables->efi_memmap[num_mds]; + efi_memory_desc_t *dom_md = &tables->efi_memmap[tables->num_mds]; u64 start = md->phys_addr; u64 size = md->num_pages << EFI_PAGE_SHIFT; u64 end = start + size; @@ -267,7 +299,7 @@ complete_dom0_memmap(struct domain *d, /* Copy descriptor. */ *dom_md = *md; dom_md->virt_addr = 0; - num_mds++; + tables->num_mds++; break; case EFI_MEMORY_MAPPED_IO_PORT_SPACE: @@ -288,31 +320,55 @@ complete_dom0_memmap(struct domain *d, *dom_md = *md; dom_md->phys_addr = mpaddr; dom_md->virt_addr = 0; - num_mds++; + tables->num_mds++; break; case EFI_CONVENTIONAL_MEMORY: case EFI_LOADER_CODE: case EFI_LOADER_DATA: case EFI_BOOT_SERVICES_CODE: - case EFI_BOOT_SERVICES_DATA: - if (!(md->attribute & EFI_MEMORY_WB)) - break; + case EFI_BOOT_SERVICES_DATA: { + u64 dom_md_start; + u64 dom_md_end; + unsigned long left_mem = + (unsigned long)(d->max_pages - d->tot_pages) << + PAGE_SHIFT; - start = max(FW_END_PADDR, start); - end = min(start + dom_mem, end); - if (end <= start) + if (!(md->attribute & EFI_MEMORY_WB)) break; - dom_md->type = EFI_CONVENTIONAL_MEMORY; - dom_md->phys_addr = start; - dom_md->virt_addr = 0; - dom_md->num_pages = (end - start) >> EFI_PAGE_SHIFT; - dom_md->attribute = EFI_MEMORY_WB; - num_mds++; - - dom_mem -= dom_md->num_pages << EFI_PAGE_SHIFT; + dom_md_start = max(tables->fw_end_paddr, start); + dom_md_end = dom_md_start; + do { + dom_md_end = min(dom_md_end + left_mem, end); + if (dom_md_end < dom_md_start + PAGE_SIZE) + break; + + dom_md->type = EFI_CONVENTIONAL_MEMORY; + dom_md->phys_addr = dom_md_start; + dom_md->virt_addr = 0; + dom_md->num_pages = + (dom_md_end - dom_md_start) >> + EFI_PAGE_SHIFT; + dom_md->attribute = EFI_MEMORY_WB; + + assign_new_domain0_range(d, dom_md); + /* + * recalculate left_mem. + * we might already allocated memory in + * this region because of kernel loader. + * So we might consumed less than + * (dom_md_end - dom_md_start) above. + */ + left_mem = (unsigned long) + (d->max_pages - d->tot_pages) << + PAGE_SHIFT; + } while (left_mem > 0 && dom_md_end < end); + + if (!(dom_md_end < dom_md_start + PAGE_SIZE)) + tables->num_mds++; break; + } case EFI_UNUSABLE_MEMORY: case EFI_PAL_CODE: @@ -326,7 +382,7 @@ complete_dom0_memmap(struct domain *d, dom_md->virt_addr = 0; dom_md->num_pages = (end - start) >> EFI_PAGE_SHIFT; dom_md->attribute = EFI_MEMORY_WB; - num_mds++; + tables->num_mds++; break; default: @@ -335,34 +391,13 @@ complete_dom0_memmap(struct domain *d, "unhandled MDT entry type %u\n", md->type); } } - BUG_ON(num_mds > NUM_MEM_DESCS); + BUG_ON(tables->fw_tables_size < + sizeof(*tables) + + sizeof(tables->efi_memmap[0]) * tables->num_mds); - sort(tables->efi_memmap, num_mds, sizeof(efi_memory_desc_t), + sort(tables->efi_memmap, tables->num_mds, sizeof(efi_memory_desc_t), efi_mdt_cmp, NULL); - /* setup_guest() @ libxc/xc_linux_build() arranges memory for domU. - * however no one arranges memory for dom0, - * instead we allocate pages manually. - */ - for (i = 0; i < num_mds; i++) { - md = &tables->efi_memmap[i]; - - if (md->type == EFI_LOADER_DATA || - md->type == EFI_PAL_CODE || - md->type == EFI_CONVENTIONAL_MEMORY) { - unsigned long start = md->phys_addr & PAGE_MASK; - unsigned long end = md->phys_addr + - (md->num_pages << EFI_PAGE_SHIFT); - - if (end == start) { - /* md->num_pages = 0 is allowed. */ - continue; - } - - for (addr = start; addr < end; addr += PAGE_SIZE) - assign_new_domain0_page(d, addr); - } - } // Map low-memory holes & unmapped MMIO for legacy drivers for (addr = 0; addr < ONE_MB; addr += PAGE_SIZE) { if (domain_page_mapped(d, addr)) @@ -375,8 +410,8 @@ complete_dom0_memmap(struct domain *d, flags); } } - setup_dom0_memmap_info(d, tables, &num_mds); - return num_mds; + setup_dom0_memmap_info(d, tables); + return tables->num_mds; } /* diff --git a/xen/arch/ia64/xen/dom_fw_domu.c b/xen/arch/ia64/xen/dom_fw_domu.c index d930642b33..fe8b346fee 100644 --- a/xen/arch/ia64/xen/dom_fw_domu.c +++ b/xen/arch/ia64/xen/dom_fw_domu.c @@ -61,19 +61,14 @@ void efi_systable_init_domu(struct fw_tables *tables) BUG_ON(i > NUM_EFI_SYS_TABLES); } -#define MAKE_MD(typ, attr, start, end) \ - xen_ia64_efi_make_md((tables), &(i), (typ), (attr), (start), (end)) - int complete_domu_memmap(domain_t * d, struct fw_tables *tables, unsigned long maxmem, - int num_mds, unsigned long memmap_info_pfn, unsigned long memmap_info_num_pages) { efi_memory_desc_t *md; - int i = num_mds; /* for MAKE_MD */ int create_memmap = 0; xen_ia64_memmap_info_t *memmap_info; unsigned long memmap_info_size; @@ -142,12 +137,12 @@ complete_domu_memmap(domain_t * d, memmap_info->efi_memmap_size = 1 * sizeof(md[0]); md = (efi_memory_desc_t *) & memmap_info->memdesc; - md[num_mds].type = EFI_CONVENTIONAL_MEMORY; - md[num_mds].pad = 0; - md[num_mds].phys_addr = 0; - md[num_mds].virt_addr = 0; - md[num_mds].num_pages = maxmem >> EFI_PAGE_SHIFT; - md[num_mds].attribute = EFI_MEMORY_WB; + md->type = EFI_CONVENTIONAL_MEMORY; + md->pad = 0; + md->phys_addr = 0; + md->virt_addr = 0; + md->num_pages = maxmem >> EFI_PAGE_SHIFT; + md->attribute = EFI_MEMORY_WB; } memmap_start = &memmap_info->memdesc; @@ -175,43 +170,61 @@ complete_domu_memmap(domain_t * d, start = md->phys_addr; end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT); - if (start < FW_END_PADDR) - start = FW_END_PADDR; + if (start < tables->fw_end_paddr) + start = tables->fw_end_paddr; if (end <= start) continue; /* exclude [paddr_start, paddr_end) */ if (paddr_end <= start || end <= paddr_start) { - MAKE_MD(EFI_CONVENTIONAL_MEMORY, EFI_MEMORY_WB, start, - end); + xen_ia64_efi_make_md(&tables-> + efi_memmap[tables->num_mds], + EFI_CONVENTIONAL_MEMORY, + EFI_MEMORY_WB, start, end); + tables->num_mds++; } else if (paddr_start <= start && paddr_end < end) { - MAKE_MD(EFI_CONVENTIONAL_MEMORY, EFI_MEMORY_WB, - paddr_end, end); + xen_ia64_efi_make_md(&tables-> + efi_memmap[tables->num_mds], + EFI_CONVENTIONAL_MEMORY, + EFI_MEMORY_WB, paddr_end, end); + tables->num_mds++; } else if (start < paddr_start && end <= paddr_end) { - MAKE_MD(EFI_CONVENTIONAL_MEMORY, EFI_MEMORY_WB, start, - paddr_start); + xen_ia64_efi_make_md(&tables-> + efi_memmap[tables->num_mds], + EFI_CONVENTIONAL_MEMORY, + EFI_MEMORY_WB, start, paddr_start); + tables->num_mds++; } else { - MAKE_MD(EFI_CONVENTIONAL_MEMORY, EFI_MEMORY_WB, start, - paddr_start); - MAKE_MD(EFI_CONVENTIONAL_MEMORY, EFI_MEMORY_WB, - paddr_end, end); + xen_ia64_efi_make_md(&tables-> + efi_memmap[tables->num_mds], + EFI_CONVENTIONAL_MEMORY, + EFI_MEMORY_WB, start, paddr_start); + tables->num_mds++; + xen_ia64_efi_make_md(&tables-> + efi_memmap[tables->num_mds], + EFI_CONVENTIONAL_MEMORY, + EFI_MEMORY_WB, paddr_end, end); + tables->num_mds++; } } /* memmap info page. */ - MAKE_MD(EFI_RUNTIME_SERVICES_DATA, EFI_MEMORY_WB, paddr_start, - paddr_end); + xen_ia64_efi_make_md(&tables->efi_memmap[tables->num_mds], + EFI_RUNTIME_SERVICES_DATA, EFI_MEMORY_WB, + paddr_start, paddr_end); + tables->num_mds++; /* Create an entry for IO ports. */ - MAKE_MD(EFI_MEMORY_MAPPED_IO_PORT_SPACE, EFI_MEMORY_UC, - IO_PORTS_PADDR, IO_PORTS_PADDR + IO_PORTS_SIZE); + xen_ia64_efi_make_md(&tables->efi_memmap[tables->num_mds], + EFI_MEMORY_MAPPED_IO_PORT_SPACE, EFI_MEMORY_UC, + IO_PORTS_PADDR, IO_PORTS_PADDR + IO_PORTS_SIZE); + tables->num_mds++; - num_mds = i; - sort(tables->efi_memmap, num_mds, sizeof(efi_memory_desc_t), + sort(tables->efi_memmap, tables->num_mds, sizeof(efi_memory_desc_t), efi_mdt_cmp, NULL); xen_ia64_dom_fw_unmap(d, memmap_info); - return num_mds; + return tables->num_mds; } /* diff --git a/xen/arch/ia64/xen/dom_fw_utils.c b/xen/arch/ia64/xen/dom_fw_utils.c index 5fd2429723..1369b05560 100644 --- a/xen/arch/ia64/xen/dom_fw_utils.c +++ b/xen/arch/ia64/xen/dom_fw_utils.c @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -70,6 +71,8 @@ static void dom_fw_domain_init(struct domain *d, struct fw_tables *tables) static int dom_fw_set_convmem_end(struct domain *d) { + unsigned long gpaddr; + size_t size; xen_ia64_memmap_info_t *memmap_info; efi_memory_desc_t *md; void *p; @@ -79,27 +82,24 @@ static int dom_fw_set_convmem_end(struct domain *d) if (d->shared_info->arch.memmap_info_pfn == 0) return -EINVAL; - memmap_info = - domain_mpa_to_imva(d, - d->shared_info->arch. - memmap_info_pfn << PAGE_SHIFT); - if (memmap_info->efi_memmap_size == 0 - || memmap_info->efi_memdesc_size != sizeof(*md) - || memmap_info->efi_memdesc_version != - EFI_MEMORY_DESCRIPTOR_VERSION) + gpaddr = d->shared_info->arch.memmap_info_pfn << PAGE_SHIFT; + size = d->shared_info->arch.memmap_info_num_pages << PAGE_SHIFT; + memmap_info = _xmalloc(size, __alignof__(*memmap_info)); + if (memmap_info == NULL) + return -ENOMEM; + dom_fw_copy_from(memmap_info, d, gpaddr, size); + if (memmap_info->efi_memmap_size == 0 || + memmap_info->efi_memdesc_size != sizeof(*md) || + memmap_info->efi_memdesc_version != EFI_MEMORY_DESCRIPTOR_VERSION || + sizeof(*memmap_info) + memmap_info->efi_memmap_size > size || + memmap_info->efi_memmap_size / memmap_info->efi_memdesc_size == 0) { + xfree(memmap_info); return -EINVAL; - - /* only 1page case is supported */ - if (d->shared_info->arch.memmap_info_num_pages != 1) - return -ENOSYS; + } memmap_start = &memmap_info->memdesc; memmap_end = memmap_start + memmap_info->efi_memmap_size; - /* XXX Currently the table must be in a single page. */ - if ((unsigned long)memmap_end > (unsigned long)memmap_info + PAGE_SIZE) - return -EINVAL; - /* sort it bofore use * XXX: this is created by user space domain builder so that * we should check its integrity */ @@ -122,6 +122,9 @@ static int dom_fw_set_convmem_end(struct domain *d) md->num_pages > 0 && d->arch.convmem_end < end) d->arch.convmem_end = end; } + + dom_fw_copy_to(d, gpaddr, memmap_info, size); + xfree(memmap_info); return 0; } @@ -135,22 +138,62 @@ assign_new_domain_page_if_dom0(struct domain *d, unsigned long mpaddr) assign_new_domain0_page(d, mpaddr); } -static void -dom_fw_setup_for_domain_restore(domain_t *d, unsigned long maxmem) +static void dom_fw_setup_for_domain_restore(domain_t * d, unsigned long maxmem) { assign_new_domain_page(d, FW_HYPERCALL_BASE_PADDR); dom_fw_domain_init(d, domain_mpa_to_imva(d, FW_TABLES_BASE_PADDR)); d->arch.convmem_end = maxmem; } +/* copy memory range to domain pseudo physical address space */ +void +dom_fw_copy_to(struct domain *d, unsigned long dest_gpaddr, + void *src, size_t size) +{ + while (size > 0) { + unsigned long page_offset = dest_gpaddr & ~PAGE_MASK; + size_t copy_size = size; + void *dest; + + if (page_offset + copy_size > PAGE_SIZE) + copy_size = PAGE_SIZE - page_offset; + dest = domain_mpa_to_imva(d, dest_gpaddr); + memcpy(dest, src, copy_size); + + src += copy_size; + dest_gpaddr += copy_size; + size -= copy_size; + } +} + +/* copy memory range from domain pseudo physical address space */ +void +dom_fw_copy_from(void *dest, struct domain *d, unsigned long src_gpaddr, + size_t size) +{ + while (size > 0) { + unsigned long page_offset = src_gpaddr & ~PAGE_MASK; + size_t copy_size = size; + void *src; + + if (page_offset + copy_size > PAGE_SIZE) + copy_size = PAGE_SIZE - page_offset; + src = domain_mpa_to_imva(d, src_gpaddr); + memcpy(dest, src, copy_size); + + dest += copy_size; + src_gpaddr += copy_size; + size -= copy_size; + } +} + int dom_fw_setup(domain_t * d, unsigned long bp_mpa, unsigned long maxmem) { int old_domu_builder = 0; struct xen_ia64_boot_param *bp; - struct fw_tables *imva_tables_base; BUILD_BUG_ON(sizeof(struct fw_tables) > - (FW_TABLES_END_PADDR - FW_TABLES_BASE_PADDR)); + (FW_TABLES_END_PADDR_MIN - FW_TABLES_BASE_PADDR)); if (bp_mpa == 0) { /* bp_mpa == 0 means this is domain restore case. */ @@ -190,10 +233,6 @@ int dom_fw_setup(domain_t * d, unsigned long bp_mpa, unsigned long maxmem) } } - /* Create page for FW tables. */ - assign_new_domain_page_if_dom0(d, FW_TABLES_BASE_PADDR); - imva_tables_base = (struct fw_tables *)domain_mpa_to_imva - (d, FW_TABLES_BASE_PADDR); /* Create page for acpi tables. */ if (d != dom0 && old_domu_builder) { struct fake_acpi_tables *imva; @@ -203,20 +242,81 @@ int dom_fw_setup(domain_t * d, unsigned long bp_mpa, unsigned long maxmem) if (d == dom0 || old_domu_builder) { int ret; unsigned long imva_hypercall_base; + size_t fw_tables_size; + struct fw_tables *fw_tables; + unsigned long gpaddr; /* Create page for hypercalls. */ assign_new_domain_page_if_dom0(d, FW_HYPERCALL_BASE_PADDR); imva_hypercall_base = (unsigned long)domain_mpa_to_imva (d, FW_HYPERCALL_BASE_PADDR); + /* Estimate necessary efi memmap size and allocate memory */ + fw_tables_size = sizeof(*fw_tables) + + (ia64_boot_param->efi_memmap_size / + ia64_boot_param->efi_memdesc_size + NUM_MEM_DESCS) * + sizeof(fw_tables->efi_memmap[0]); + if (fw_tables_size < + FW_TABLES_END_PADDR_MIN - FW_TABLES_BASE_PADDR) + fw_tables_size = + FW_TABLES_END_PADDR_MIN - FW_TABLES_BASE_PADDR; + fw_tables_size = (fw_tables_size + ((1UL << EFI_PAGE_SHIFT) - 1)) + & ~((1UL << EFI_PAGE_SHIFT) - 1); + fw_tables = + (struct fw_tables *)_xmalloc(fw_tables_size, + __alignof__(*fw_tables)); + if (fw_tables == NULL) { + dprintk(XENLOG_INFO, + "can't allocate fw_tables memory size = %ld\n", + fw_tables_size); + return -ENOMEM; + } + memset(fw_tables, 0, fw_tables_size); + BUILD_BUG_ON(FW_END_PADDR_MIN != FW_TABLES_END_PADDR_MIN); + fw_tables->fw_tables_size = fw_tables_size; + fw_tables->fw_end_paddr = FW_TABLES_BASE_PADDR + fw_tables_size; + fw_tables->fw_tables_end_paddr = + FW_TABLES_BASE_PADDR + fw_tables_size; + fw_tables->num_mds = 0; + + /* It is necessary to allocate pages before dom_fw_init() + * dom_fw_init() uses up page to d->max_pages. + */ + for (gpaddr = FW_TABLES_BASE_PADDR; + gpaddr < fw_tables->fw_end_paddr; gpaddr += PAGE_SIZE) + assign_new_domain_page_if_dom0(d, gpaddr); + ret = dom_fw_init(d, d->arch.breakimm, bp, - imva_tables_base, imva_hypercall_base, - maxmem); - if (ret < 0) + fw_tables, imva_hypercall_base, maxmem); + if (ret < 0) { + xfree(fw_tables); return ret; + } + if (sizeof(*fw_tables) + + fw_tables->num_mds * sizeof(fw_tables->efi_memmap[0]) > + fw_tables_size) { + panic("EFI memmap too large. Increase NUM_MEM_DESCS.\n" + "fw_table_size %ld > %ld num_mds %ld " + "NUM_MEM_DESCS %d.\n", + fw_tables_size, fw_tables->fw_tables_size, + fw_tables->num_mds, NUM_MEM_DESCS); + } + fw_tables_size = sizeof(*fw_tables) + + fw_tables->num_mds * sizeof(fw_tables->efi_memmap[0]); + + /* clear domain builder internal use member */ + fw_tables->fw_tables_size = 0; + fw_tables->fw_end_paddr = 0; + fw_tables->fw_tables_end_paddr = 0; + fw_tables->num_mds = 0; + + /* copy fw_tables into domain pseudo physical address space */ + dom_fw_copy_to(d, FW_TABLES_BASE_PADDR, fw_tables, + fw_tables_size); + xfree(fw_tables); } - dom_fw_domain_init(d, imva_tables_base); + dom_fw_domain_init(d, domain_mpa_to_imva(d, FW_TABLES_BASE_PADDR)); return dom_fw_set_convmem_end(d); } diff --git a/xen/include/asm-ia64/dom_fw.h b/xen/include/asm-ia64/dom_fw.h index 3bef4bf887..9fa5198025 100644 --- a/xen/include/asm-ia64/dom_fw.h +++ b/xen/include/asm-ia64/dom_fw.h @@ -8,7 +8,8 @@ /* Portion of guest physical memory space reserved for PAL/SAL/EFI/ACPI data and code. */ #define FW_BASE_PADDR 0x0000UL -#define FW_END_PADDR 0x3000UL +/* It is assumed that FW_END_PADDR_MIN = FW_TABLES_END_PADDR_MIN */ +#define FW_END_PADDR_MIN 0x3000UL /* This is used to determined the portion of a domain's metaphysical memory space reserved for the hypercall patch table. */ @@ -29,7 +30,7 @@ /* Base and end guest physical address of EFI and SAL (non-ACPI) tables. */ #define FW_TABLES_BASE_PADDR 0x2000UL -#define FW_TABLES_END_PADDR 0x3000UL +#define FW_TABLES_END_PADDR_MIN 0x3000UL /* Hypercalls number have a low part and a high part. diff --git a/xen/include/asm-ia64/dom_fw_common.h b/xen/include/asm-ia64/dom_fw_common.h index 6afd651e2d..de24d253bc 100644 --- a/xen/include/asm-ia64/dom_fw_common.h +++ b/xen/include/asm-ia64/dom_fw_common.h @@ -64,16 +64,26 @@ struct fw_tables { /* End of SAL descriptors. Do not forget to update checkum bound. */ fpswa_interface_t fpswa_inf; - efi_memory_desc_t efi_memmap[NUM_MEM_DESCS]; unsigned long func_ptrs[2*NFUNCPTRS]; struct xen_sal_data sal_data; unsigned char fw_vendor[sizeof(FW_VENDOR)]; + + /* + * These four member for domain builder internal use at virtualized + * efi memmap creation. They should be zero-cleared after use. + */ + unsigned long fw_tables_size; + unsigned long fw_end_paddr; + unsigned long fw_tables_end_paddr; + unsigned long num_mds; + + efi_memory_desc_t efi_memmap[0]; }; #define FW_FIELD_MPA(field) \ FW_TABLES_BASE_PADDR + offsetof(struct fw_tables, field) void -xen_ia64_efi_make_md(struct fw_tables *tables, int *index, +xen_ia64_efi_make_md(efi_memory_desc_t *md, uint32_t type, uint64_t attr, uint64_t start, uint64_t end); uint8_t generate_acpi_checksum(void *tbl, unsigned long len); diff --git a/xen/include/asm-ia64/dom_fw_dom0.h b/xen/include/asm-ia64/dom_fw_dom0.h index 1a496bc192..11e199cb5c 100644 --- a/xen/include/asm-ia64/dom_fw_dom0.h +++ b/xen/include/asm-ia64/dom_fw_dom0.h @@ -25,11 +25,7 @@ struct fw_tables; struct domain; void efi_systable_init_dom0(struct fw_tables *tables); -int -complete_dom0_memmap(struct domain *d, - struct fw_tables *tables, - unsigned long maxmem, - int num_mds); +int complete_dom0_memmap(struct domain *d, struct fw_tables *tables); #endif /* __ASM_IA64_DOM_FW_DOM0_H__ */ /* diff --git a/xen/include/asm-ia64/dom_fw_domu.h b/xen/include/asm-ia64/dom_fw_domu.h index 6199c4c3d3..7f15ddb128 100644 --- a/xen/include/asm-ia64/dom_fw_domu.h +++ b/xen/include/asm-ia64/dom_fw_domu.h @@ -29,9 +29,9 @@ int complete_domu_memmap(domain_t *d, struct fw_tables *tables, unsigned long maxmem, - int num_mds, unsigned long memmap_info_pfn, unsigned long reserved_size); + #endif /* __ASM_IA64_DOM_FW_DOMU_H__ */ /* * Local variables: diff --git a/xen/include/asm-ia64/dom_fw_utils.h b/xen/include/asm-ia64/dom_fw_utils.h index 1cb047d810..1d71cdbb2a 100644 --- a/xen/include/asm-ia64/dom_fw_utils.h +++ b/xen/include/asm-ia64/dom_fw_utils.h @@ -26,6 +26,10 @@ int xen_ia64_fpswa_revision(struct domain *d, unsigned int *revision); int xen_ia64_is_vcpu_allocated(struct domain *d, uint32_t vcpu); int xen_ia64_is_running_on_sim(struct domain *unused); int xen_ia64_is_dom0(struct domain *d); +void dom_fw_copy_to(struct domain *d, unsigned long dest_gpaddr, + void *src, size_t size); +void dom_fw_copy_from(void* dest, struct domain *d, unsigned long src_gpaddr, + size_t size); #endif /* __ASM_XEN_IA64_DOM_FW_UTILS_H__ */ -- 2.30.2